#include <stdlib.h>
#include <pthread.h>
#include "soapH.h"
#include "netbook.nsmap"
#include "moddb/mydb.h"
#include "moddb/mydata/model.h"

// help macros.
#define true 1
#define false 0

#define SAFE_MALLOC(dest, size) do {\
    dest = (typeof(dest))malloc(size);\
    memset(dest, 0, size);}while (0)

#define SAFE_FREE(ptr) do {\
    if (ptr) free(ptr);	\
    ptr = NULL;}while (0)

#define SAFE_SOAP_MALLOC(soap, dest, size) do {\
    dest = (typeof(dest))soap_malloc(soap, size);\
    memset(dest, 0, size);}while (0)


// about gsoap sever.
#define TIME_LIMIT  (32)    // bind time limits. after this time, give up trying.
#define BACKLOG	(150)	    // max request back log.
#define MIN_THREAD  (10)    // max initial threads.
#define MAX_THREAD  (100)   // max total threads at a time.
#define MAX_SOCKET  (1000)  // enable MAX_SOCKET requests at a time.

static SOAP_SOCKET queue[MAX_SOCKET];	// our request sockets queue.
static pthread_mutex_t mutex_queue;	// the mutex semaphore for the sockets queue.
static pthread_cond_t cond_queue;  // the conditional semaphore for the sockets queue.
int out = 0, in = 0;	// queue in & out index.

static void *process_queue(void *);
static int enqueue(SOAP_SOCKET);
static SOAP_SOCKET dequeue(void);

/**********************************\
 * main()
\**********************************/
int
main(int argc, char **argv)
{
    SOAP_SOCKET m, s; /* master and slave sockets */
    struct soap soap;
    soap_init(&soap);
    soap_set_namespaces(&soap, namespaces);

    // init the database.
    mydata_init("mydata_real");

    // server start..
    if (argc < 2) {
	//soap_serve(&soap);	/* serve as CGI application */
	//soap_serve(&soap);
	//soap_end(&soap);
	printf("usage: xxx port\n");
    }
    else {
	struct soap *soap_thr[MIN_THREAD];
	pthread_t tid[MIN_THREAD];

	// set soap struct.
	//soap.send_timeout = 5;
	//soap.recv_timeout = 5;
	//soap.accept_timeout = 3600;
	//soap.max_keep_alive = 4;

	// initial locks conds.
	pthread_mutex_init(&mutex_queue, NULL);
	pthread_cond_init(&cond_queue, NULL);
	
	// try bind untill success. wait 
	int t=1;
	m = soap_bind(&soap, NULL, atoi(argv[1]), BACKLOG);
	while (!soap_valid_socket(m) && (t <= TIME_LIMIT)){
	    soap_print_fault(&soap, stderr);
	    printf("try bind %d second%s later.\n", t, t > 1 ? "s" : "");
	    sleep(t);
	    t *= 2;
	    m = soap_bind(&soap, NULL, atoi(argv[1]), BACKLOG);
	}
	if (!soap_valid_socket(m)) {
	    soap_print_fault(&soap, stderr);
	    printf("Failed!\n", t, t > 1 ? "s" : "");
	    exit(1);
	}
	fprintf(stderr, "Socket connection successful: master socket = %d\n", m);

	// generate service threads.
	int i;
	for (i = 0; i < MIN_THREAD; i++) {
	    soap_thr[i] = soap_copy(&soap);
	    fprintf(stderr, "start initial thread#%d..\n", i);
	    pthread_create(&tid[i], NULL, (void *(*)(void *))process_queue, (void *)soap_thr[i]);
	}

	fprintf(stderr, "start serving...\n");
	while(true) {
	    s = soap_accept(&soap);
	    fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);
	    if (!soap_valid_socket(s)) {// how to do here is the best!!!!!!
		if (soap.errnum) {
		    soap_print_fault(&soap, stderr);
		    continue;
		}
		else {// what's this?
		    fprintf(stderr, "server time out!\n");
		    continue;
		}
	    } 
	    fprintf(stderr, "Accepted connection from IP = %d.%d.%d.%d\n",
		    ((soap.ip)>>24)&0xFF,((soap.ip)>>16)&0xFF,((soap.ip)>>8)&0xFF,(soap.ip)&0xFF);

	    while (enqueue(s) == SOAP_EOM) {
		sleep(1);// wait some thread to consume some sockets.
	    }
	}
	for (i = 0; i < MIN_THREAD; i++) {
	    while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM) {
		sleep(1);
	    }
	}

	for (i = 0; i < MIN_THREAD; i++) {
	    fprintf(stderr, "waiting for thread %d to terminate...\n",i);
	    pthread_join(tid[i], NULL);
	    fprintf(stderr, "terminated\n");
	    soap_done(soap_thr[i]);
	    free(soap_thr[i]);
	}
	pthread_mutex_destroy(&mutex_queue);
	pthread_cond_destroy(&cond_queue);
    }
    soap_done(&soap);
    return 0;
} 

static void *
process_queue(void *soap)
{
    struct soap *tsoap = (struct soap *)soap;

    while (true) {
	tsoap->socket = dequeue();
	if (!soap_valid_socket(tsoap->socket)) {// concern the main(),this only happen when to exit.
	    break;
	}
	fprintf(stderr, "begin:#%u\n",pthread_self());
	soap_serve(tsoap);
	soap_destroy(tsoap);
	soap_end(tsoap);
	fprintf(stderr, "end:#%u\n",pthread_self());
    }
    return NULL;
}

/**************************************\
 * sockets queue: enqueue & dequeue
\**************************************/
static int
enqueue(SOAP_SOCKET sock)
{
    int ret = SOAP_OK;
    int next;
    pthread_mutex_lock(&mutex_queue);
    next = in + 1;
    if (next >= MAX_SOCKET) {
	next = 0;
    }
    if (next == out) {
	ret = SOAP_EOM;
    }
    else {
	queue[in] = sock;
	in = next;
    }
    pthread_cond_signal(&cond_queue);
    pthread_mutex_unlock(&mutex_queue);

    return ret;
}

static SOAP_SOCKET
dequeue()
{
    SOAP_SOCKET sock;
    pthread_mutex_lock(&mutex_queue);
    while (out == in) {
	pthread_cond_wait(&cond_queue, &mutex_queue);
    }
    sock = queue[out++];
    if (out >= MAX_SOCKET) {
	out = 0;
    }
    pthread_mutex_unlock(&mutex_queue);
    return sock;
}

// help static inline functions.
static inline int user_copy_tables(struct soap *soap, UserStruct *dest, User *src, uint32_t size);
static inline int note_copy_tables(struct soap *soap, NoteStruct *dest, Note *src, uint32_t field, uint32_t size);
static inline int free_usertables(User *src, uint32_t size);
static inline int free_notetables(Note *src, uint32_t size);

// parameter checking.
#define SESSION_LEN 36
#define MAX_NICKNAME_LEN    24
#define MAX_MAIL_LEN	64
#define MAX_PASSWD_LEN	16	
#define MAX_TITLE_LEN	255
#define MAX_CONTENT_LEN	(1<<20)

// assume all the soap structs are "soap".
#define CHECK_SESSION(session)	do {\
    if (!session || strlen(session) != SESSION_LEN) {\
	return soap_sender_fault(soap, "session fault.", NULL); }}while (0)
#define CHECK_MAIL(mail)   do {\
    if (!mail || !(*mail) || strlen(mail) > MAX_MAIL_LEN) {\
	return soap_sender_fault(soap, "mail fault", NULL); }}while (0)
#define CHECK_PASSWD(passwd)	do {\
    if (!passwd || !(*passwd) || strlen(passwd) > MAX_PASSWD_LEN) {\
	return soap_sender_fault(soap, "passwd fault", NULL); }}while (0)
#define CHECK_TITLE(title)  do {\
    if (title && strlen(title) > MAX_TITLE_LEN) {\
	return soap_sender_fault(soap, "title too long.", NULL); }\
    char *default_title = "untitled note";\
    if (!title || !(*title)) {\
	title = strdup("untitled note"); } }while(0)
#define CHECK_CONTENT(content)	do {\
    if (content && strlen(content) > MAX_CONTENT_LEN) {\
	return soap_sender_fault(soap, "content too long.", NULL); }}while (0)

/**** APIs ****/
/** Authentication **/
/*
 * @IN:
 *  mail, string(0, 64)
 *  passwd, string(0, 16)
 * @OUT:
 *  session, string[16]
 */
int ns__login(struct soap *soap, char *mail, char *passwd, char **session)
{
    // parameter checing.
    CHECK_MAIL(mail);
    CHECK_PASSWD(passwd);

    // start
    uint32_t user_id;
    if (!mydata_mail_passwd_match(mail, passwd, &user_id)) {
	return soap_sender_fault(soap, "mail and password mismatch.", NULL);}
    char *uuid;
    if (mydata_session_user_exist(user_id, &uuid)) {// login already.
	*session = soap_strdup(soap, uuid);
	SAFE_FREE(uuid);
	return SOAP_OK;
    }
    Session new_session = {
	//.uuid
	.user_id = user_id,
	//.time_create
	.attribute = 0,
    };
    if (mydata_insert_session(&new_session) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *session = soap_strdup(soap, new_session.uuid);
    // free memory.
    SAFE_FREE(new_session.time_create);
    return SOAP_OK;
}

/*
 * @IN:
 *  session, string[16]
 * @OUT:
 *  status, int
 */
int ns__logout(struct soap *soap, char *session, int *status)
{
    // parameter checking.
    CHECK_SESSION(session);

    // start
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {// not login yet.
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_remove_session(session) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *status = 0;
    return SOAP_OK;
}

/** User **/
/*
 * @IN:
 *  nickname, string(0, 24)
 *  mail, string(0, 64)
 *  passwd, string(0, 16)
 * @OUT:
 *  user, UserStruct
 */
int ns__register(struct soap *soap, char *mail, char *passwd, UserStruct **user)
{
    // parameter checking.
    CHECK_MAIL(mail);
    CHECK_PASSWD(passwd);

    // start.
    if (mydata_user_mail_exist(mail, NULL)) {
	return soap_sender_fault(soap, "mail exist.", NULL); }
    User *new_user;
    SAFE_MALLOC(new_user, sizeof(User));
    *new_user = (User){
	//.id 
	.nickname = strdup("NetBook"),
	.mail = strdup(mail),
	.passwd = strdup(passwd),
	//.time_reg
	//.time_lastlogin
	//.time_lastupdate
	.attribute = 0
    };
    if (mydata_insert_user(new_user) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    SAFE_SOAP_MALLOC(soap, *user, sizeof(UserStruct));
    user_copy_tables(soap, *user, new_user, 1);
    // free memory.
    free_usertables(new_user, 1);
    return SOAP_OK;

}


int ns__setMyAttribute(struct soap *soap, char *session, uint8_t attribute, int *status)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    // prepare new user.
    User new_user = {
	.id = user_id,
	.attribute = attribute,
    };
    if (mydata_update_user(&new_user, USER_NICKNAME) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *status = 0;
    return SOAP_OK;
}

int ns__changeMyNickname(struct soap *soap, char *session, char *nickname, int *status)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    // prepare new user.
    User new_user = {
	.id = user_id,
	.nickname = nickname,
    };
    if (mydata_update_user(&new_user, USER_NICKNAME) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *status = 0;
    return SOAP_OK;
}

int ns__changeMyPasswd(struct soap *soap, char *session, char *old_USCOREpasswd, char *new_USCOREpasswd, int *status)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    if (!mydata_id_passwd_match(user_id, old_USCOREpasswd)) {// check if the old passwd right.
	return soap_sender_fault(soap, "old passwd error.", NULL);}
    // prepare new user.
    User new_user = {
	.id = user_id,
	.passwd = new_USCOREpasswd,
    };
    if (mydata_update_user(&new_user, USER_NICKNAME) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *status = 0;
    return SOAP_OK;
}

/*
 * @IN:
 *  session, string[36]
 *  user_id, uint32_t
 * @OUT:
 *  user, UserStruct
 */
int ns__getUserById(struct soap *soap, char *session, uint32_t user_USCOREid, UserStruct **user)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    if (mydata_session_exist(session, NULL) < 0) { // must login to check others info.
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    User *user_get;
    if (mydata_get_user_by_id(user_USCOREid, &user_get) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }

    SAFE_SOAP_MALLOC(soap, *user, sizeof(User));
    user_copy_tables(soap, *user, user_get, 1);
    // free memory.
    free_usertables(user_get, 1);
    return SOAP_OK;
}

/*
 * @IN:
 *  session, string[36]
 *  mail, string(0, 64)
 * @OUT:
 *  user, UserStruct
 */
int ns__getUserByMail(struct soap *soap, char *session, char *mail, UserStruct **user)
{
    // parameter checking.
    CHECK_SESSION(session);
    CHECK_MAIL(mail);
    
    // start.
    if (mydata_session_exist(session, NULL) < 0) { // must login to check others info.
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    User *user_get;
    if (mydata_get_user_by_mail(mail, &user_get) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }

    SAFE_SOAP_MALLOC(soap, *user, sizeof(User));
    user_copy_tables(soap, *user, user_get, 1);
    // free memory.
    free_usertables(user_get, 1);
    return SOAP_OK;
}

int ns__getMyself(struct soap *soap, char *session, UserStruct **user)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    User *user_get;
    if (mydata_get_user_by_id(user_id, &user_get) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }

    SAFE_SOAP_MALLOC(soap, *user, sizeof(User));
    user_copy_tables(soap, *user, user_get, 1);
    // free memory.
    free_usertables(user_get, 1);
    return SOAP_OK;
}
int ns__getUserList(struct soap *soap, char *session, UserArray **result)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    if (mydata_session_exist(session, NULL) < 0) { // must login to check others info.
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    ArrayTable array;
    if (mydata_get_user_list(&array) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    SAFE_SOAP_MALLOC(soap, *result, sizeof(UserArray));
    SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (array.size)*sizeof(UserStruct));
    (*result)->__size = array.size;
    user_copy_tables(soap, (*result)->__ptr, array.ptr, array.size);
    // free memory.
    free_usertables(array.ptr, array.size);
    return SOAP_OK;
}

/** Note**/
// insert, update, remove
/*
 * @IN:
 *  session, string[16]
 *  title, string[0, 255)
 *  content, string[0, 4G)
 * @OUT:
 *  Note, NoteStruct
 */
int
ns__insertMyNote(struct soap *soap, char *session, char *title, char *content, NoteStruct **note)
{
    // parameter checking.
    CHECK_SESSION(session);
    CHECK_TITLE(title);
    CHECK_CONTENT(content);

    // start
    uint32_t user_id = 0;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL); }
    Note *new_note;
    SAFE_MALLOC(new_note, sizeof(Note));
    *new_note = (Note) {
	//.id
	.owner_id = user_id,
	//.uuid
	.title = strdup(title),
	.content = strdup(content),
	//.time_create
	//.time_lastupdate
	.version = 0,
	.attribute = 0,
    };
    if (mydata_insert_note(new_note) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    SAFE_SOAP_MALLOC(soap, *note, sizeof(NoteStruct));
    note_copy_tables(soap, *note, new_note, -1, 1);
    // free memory.
    free_notetables(new_note, 1);
    return SOAP_OK;
}

/*
 * @IN:
 *  session, string[16]
 *  title, string[0, 255)
 *  content, string[0, 4G)
 * @OUT:
 *  status, int
 */
int ns__updateMyNote(struct soap *soap, char *session, uint64_t note_USCOREid, char *title, char *content, int *status)
{
    // parameter checking.
    CHECK_SESSION(session);
    CHECK_TITLE(title);
    CHECK_CONTENT(content);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    if (!mydata_own_note(user_id, note_USCOREid)) {
	return soap_sender_fault(soap, "this not your note.", NULL);}
    // prepare new user.
    Note new_note = {
	.id = note_USCOREid,
	.title = title,
	.content = content,
    };
    if (mydata_update_note(&new_note, NOTE_TITLE|NOTE_CONTENT) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *status = 0;
    return SOAP_OK;
}

/*
 * @IN:
 *  session, string[16]
 *  note_id, uint64_t
 * @OUT:
 *  status, int
 */
int ns__removeMyNote(struct soap *soap, char *session, uint64_t note_USCOREid, int *status)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    if (!mydata_own_note(user_id, note_USCOREid)) {
	return soap_sender_fault(soap, "this not your note.", NULL);}
    if (mydata_remove_note(note_USCOREid) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    *status = 0;
    return SOAP_OK;
}

/*
 * @IN:
 *  session, string[16]
 *  note_id, uint64_t
 *  field, uint32_t
 * @OUT:
 *  note, NoteStruct
 */
int ns__getNoteById(struct soap *soap, char *session, uint64_t note_USCOREid, uint32_t field, NoteStruct **note)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    if (!mydata_note_is_public(note_USCOREid)) { // if note is not public
	uint32_t user_id;
	if (mydata_session_exist(session, &user_id) < 0) { // then you must login.
	    return soap_sender_fault(soap, "Not logged in.", NULL);}
	if (!mydata_own_note(user_id, note_USCOREid)) { // you must either own the note
	    if (!mydata_note_is_shared(note_USCOREid, user_id)) { // OR the note is shared with you.
		return soap_sender_fault(soap, "have no permission.", NULL);}
	}
    }
    Note *note_get;
    if (mydata_get_note_by_id(note_USCOREid, &note_get) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }

    SAFE_SOAP_MALLOC(soap, *note, sizeof(Note));
    note_copy_tables(soap, *note, note_get, field, 1);
    // free memory.
    free_notetables(note_get, 1);
    return SOAP_OK;
}

int
ns__getAllPublicNoteNumber(struct soap *soap, char *session, uint64_t *number)
{
    // parameter checking.
    
    // start.
    if (mydata_get_all_public_note_number(number) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    return SOAP_OK;
}

int
ns__getAllPublicNoteList(struct soap *soap, char *session, uint64_t start, uint32_t count, uint32_t field, NoteArray **result)
{
    // parameter checking.
    
    // start.
    ArrayTable array;
    if (mydata_get_all_public_note_list(start, count, &array) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    SAFE_SOAP_MALLOC(soap, *result, sizeof(NoteArray));
    SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (array.size)*sizeof(NoteStruct));
    (*result)->__size = array.size;
    note_copy_tables(soap, (*result)->__ptr, array.ptr, field, array.size);
    // free memory.
    free_notetables(array.ptr, array.size);
    return SOAP_OK;
}

int
ns__getMyNoteNumber(struct soap *soap, char *session, uint64_t *number)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    if (mydata_get_my_note_number(user_id, number) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    return SOAP_OK;
}

int
ns__getMyNoteList(struct soap *soap, char *session, uint64_t start, uint32_t count, uint32_t field, NoteArray **result)
{
    // parameter checking.
    CHECK_SESSION(session);
    
    // start.
    uint32_t user_id;
    if (mydata_session_exist(session, &user_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);}
    ArrayTable array;
    if (mydata_get_my_note_list(user_id, start, count, &array) < 0) {
	return soap_receiver_fault(soap, "mydata server error.", NULL); }
    SAFE_SOAP_MALLOC(soap, *result, sizeof(NoteArray));
    SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (array.size)*sizeof(NoteStruct));
    (*result)->__size = array.size;
    note_copy_tables(soap, (*result)->__ptr, array.ptr, field, array.size);
    // free memory.
    free_notetables(array.ptr, array.size);
    return SOAP_OK;
}

/*
int
ns__getMyNoteNumber(struct soap *soap, char *session, uint32_t *number)
{
    uint32_t my_id = 0;
    if (mydata_session_exist(session, &my_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_get_my_note_number(my_id, number) >= 0) {
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}

int
ns__getMyNoteList(struct soap *soap, char *session, uint32_t start, uint32_t count, uint32_t field, NoteArray **result)
{
    uint32_t my_id = 0;
    NoteArray notearray;
    if (mydata_session_exist(session, &my_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_get_my_note_list(my_id, start, count, field, &notearray) >= 0) {
	SAFE_SOAP_MALLOC(soap, *result, sizeof(NoteArray));
	SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (notearray.__size)*sizeof(Note));
	(*result)->__size = notearray.__size;
	note_copy_tables(soap, (*result)->__ptr, notearray.__ptr, field, notearray.__size);
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}

int
ns__getUserSharedNoteNumber(struct soap *soap, char *session, uint32_t user_USCOREid, uint32_t *number)
{
    uint32_t my_id = 0;
    if (mydata_session_exist(session, &my_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_get_user_shared_note_number(my_id, user_USCOREid, number) >= 0) {
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}

int
ns__getUserSharedNoteList(struct soap *soap, char *session, uint32_t user_USCOREid, uint32_t start, uint32_t count, uint32_t field, NoteArray **result)
{
    uint32_t my_id = 0;
    NoteArray notearray;
    if (mydata_session_exist(session, &my_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_get_user_shared_note_list(my_id, user_USCOREid, start, count, field, &notearray) >= 0) {
	SAFE_SOAP_MALLOC(soap, *result, sizeof(NoteArray));
	SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (notearray.__size)*sizeof(Note));
	(*result)->__size = notearray.__size;
	note_copy_tables(soap, (*result)->__ptr, notearray.__ptr, field, notearray.__size);
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}

int
ns__getAllSharedNoteNumber(struct soap *soap, char *session, uint64_t *number)
{
    uint32_t my_id = 0;
    if (mydata_session_exist(session, &my_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_get_all_shared_note_number(my_id, number) >= 0) {
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}
int
ns__getAllSharedNoteList(struct soap *soap, char *session, uint64_t start, uint32_t count, uint32_t field, NoteArray **result)
{
    uint32_t my_id = 0;
    NoteArray notearray;
    if (mydata_session_exist(session, &my_id) < 0) {
	return soap_sender_fault(soap, "Not logged in.", NULL);
    }
    if (mydata_get_all_shared_note_list(my_id, start, count, field, &notearray) >= 0) {
	SAFE_SOAP_MALLOC(soap, *result, sizeof(NoteArray));
	SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (notearray.__size)*sizeof(Note));
	(*result)->__size = notearray.__size;
	note_copy_tables(soap, (*result)->__ptr, notearray.__ptr, field, notearray.__size);
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}

int
ns__getUserPublicNoteNumber(struct soap *soap, char *session, uint32_t user_USCOREid, uint32_t *number)
{
    //uint32_t my_id = 0;
    //if (mydata_session_exist(session, &my_id) < 0) {
    //	return soap_sender_fault(soap, "Not logged in.", NULL);
    //}
    if (mydata_get_user_public_note_number(user_USCOREid, number) >= 0) {
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}
int
ns__getUserPublicNoteList(struct soap *soap, char *session, uint32_t user_USCOREid, uint32_t start, uint32_t count, uint32_t field, NoteArray **result)
{
    //uint32_t my_id = 0;
    //if (mydata_session_exist(session, &my_id) < 0) {
    //	return soap_sender_fault(soap, "Not logged in.", NULL);
    //}
    NoteArray notearray;
    if (mydata_get_user_public_note_list(user_USCOREid, start, count, field, &notearray) >= 0) {
	SAFE_SOAP_MALLOC(soap, *result, sizeof(NoteArray));
	SAFE_SOAP_MALLOC(soap, (*result)->__ptr, (notearray.__size)*sizeof(Note));
	(*result)->__size = notearray.__size;
	note_copy_tables(soap, (*result)->__ptr, notearray.__ptr, field, notearray.__size);
	return SOAP_OK;
    }
    return soap_receiver_fault(soap, "mydata server error.", NULL);
}

*/
// help functions.
static inline int
user_copy_tables(struct soap *soap, UserStruct *dest, User *src, uint32_t size)
{
    uint32_t i;
    for (i = 0; i < size; i++) {
	(dest)[i].id = (src)[i].id;
	(dest)[i].nickname = soap_strdup(soap, (src)[i].nickname);
	(dest)[i].mail = soap_strdup(soap, (src)[i].mail);
	(dest)[i].time_USCOREreg = soap_strdup(soap, (src)[i].time_reg);
	(dest)[i].time_USCORElastlogin = soap_strdup(soap, (src)[i].time_lastlogin);
	(dest)[i].time_USCORElastupdate =soap_strdup(soap, (src)[i].time_lastupdate);
	(dest)[i].attribute = (src)[i].attribute;
    }
    return 0;
}

static inline int
note_copy_tables(struct soap *soap, NoteStruct *dest, Note *src, uint32_t field, uint32_t size)
{
    uint32_t i;
    for (i = 0; i < size; i++) {
	(dest)[i].id = (src)[i].id;
	if (field|NOTE_UUID) {
	    (dest)[i].uuid = soap_strdup(soap, (src)[i].uuid); }
	if (field|NOTE_TITLE) {
	    (dest)[i].title = soap_strdup(soap, (src)[i].title); }
	if (field|NOTE_CONTENT) {
	    (dest)[i].content = soap_strdup(soap, (src)[i].content); }
	if (field|NOTE_TIME_CREATE) {
	    (dest)[i].time_USCOREcreate = soap_strdup(soap, (src)[i].time_create); }
	if (field|NOTE_TIME_LASTUPDATE) {
	    (dest)[i].time_USCORElastupdate =soap_strdup(soap, (src)[i].time_lastupdate); }
	if (field|NOTE_ATTRIBUTE) {
	    (dest)[i].attribute = (src)[i].attribute; }
	if (field|NOTE_VERSION) {
	    (dest)[i].version = (src)[i].version; }
    }
    return 0;
}

static inline int
free_usertables(User *src, uint32_t size)
{
    uint32_t i;
    for (i = 0; i < size; i++) {
	SAFE_FREE((src)[i].nickname);
	SAFE_FREE((src)[i].mail);
	SAFE_FREE((src)[i].passwd);
	SAFE_FREE((src)[i].time_reg);
	SAFE_FREE((src)[i].time_lastlogin);
	SAFE_FREE((src)[i].time_lastupdate);
    }
    SAFE_FREE(src);
    return 0;
}

static inline int
free_notetables(Note *src, uint32_t size)
{
    uint32_t i;
    for (i = 0; i < size; i++) {
	SAFE_FREE((src)[i].uuid);
	SAFE_FREE((src)[i].title);
	SAFE_FREE((src)[i].content);
	SAFE_FREE((src)[i].time_create);
	SAFE_FREE((src)[i].time_lastupdate);
    }
    SAFE_FREE(src);
    return 0;
}
